﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Compiled_Tests.AutomationAbstractions;
using Tedds_Tool.Instructions;
using System.Windows;
using Tedds_Tool.Automatables.LEETModuals;
using Tedds_Tool.Automatables.LEETModuals.LEETHackModuals;
using GUI.Custom_Classes;
using LEET.CommonInterfaces;
using CommonInterfaces.Models;
using Compiled_Tests;
using LEET.CommonInterfaces.Factories;
using System.Reflection;
using LEET.CommonInterfaces.Automation;
using LEET.CommonInterfaces.Models;
using System.IO;
using LEET.DynamicLoading;

namespace Tedds_Tool.Automatables
{
    public class LEETFactory : ILEETFactory
    {
        public IBox Box { get; private set; }
        IList<ILEETModual> moduals;
        IList<ILEETHackModual> hacks;

        public LEETFactory(IBox box)
        {
            this.Box = box;
            moduals = new List<ILEETModual>();
            hacks = new List<ILEETHackModual>();
            
            PositionHack positionHack = new PositionHack();
            ScaleHack scaleHack = new ScaleHack();
            RotationHack rotationHack = new RotationHack();

            //specialCase for hacking
            ValueSetable valueSetable;
            LoadModual(valueSetable = new ValueSetable());
            valueSetable.LoadHack(positionHack);
            valueSetable.LoadHack(scaleHack);
            valueSetable.LoadHack(rotationHack);

            VerifyModual verifyModual;
            LoadModual(verifyModual = new VerifyModual());
            verifyModual.LoadHack(positionHack);
            verifyModual.LoadHack(scaleHack);
            verifyModual.LoadHack(rotationHack);
            


            //Load Hacks
            LoadModual(rotationHack);
            LoadModual(scaleHack);
            LoadModual(positionHack);

            // Load internal moduals
            LoadModual(new StartModual());
            LoadModual(new OptionModual());
            LoadModual(new TargetModual());
            LoadModual(new PauseModual());
            LoadModual(new EmbeddedScriptModual());
            LoadModual(new BreakPointModual());
            LoadModual(new CommentModual());
            LoadModual(new RuleBaseModual());

            // Load Mouse Moduals
            LoadModual(new LeftClickModual());
            LoadModual(new LeftDoubleClickModule());
            LoadModual(new LeftClickDragModule());
            LoadModual(new MoveCursorModule());
            LoadModual(new RightClickModual());
            //LoadModual(new RightDoubleClickModule());
            LoadModual(new RightClickDragModule());
            
            LoadDynamicModuals();
        }

        private void LoadDynamicModuals()
        {
            try
            {
                IEnumerable<Type> types = LEETLoader.LoadAll<ILEETActionModual>().Where(delegate(Type w){
                    try
                    {
                        return w != typeof(ValueSetable);
                    } catch {
                        return false;
                    }
                });
                foreach (Type t in types)
                {
                    try
                    {

                        ConstructorInfo info = t.GetConstructor(new Type[] { });
                        ILEETActionModual modual = info.Invoke(new object[] { }) as ILEETActionModual;
                        if (modual != null)
                            LoadModual(modual);
                    }
                    catch { }
                }
            }
            catch (ReflectionTypeLoadException e)
            {
                throw new Exception(e.Message, e);
            }
            catch (Exception e)
            {
                throw new Exception(e.Message, e);
            }
        }

        public void LoadModual(ILEETModual modual)
        {
            // if moduals contains a modual of the same type as modual don't load it again
            if (moduals.Where(w => (w.GetType() == modual.GetType())).Count() > 0)
                return;

            moduals.Add(modual);
            if (modual is ILEETHackModual)
                hacks.Add(modual as ILEETHackModual);
        }

        public ITape BuildTape(Compiled_Tests.IProcess proc, EventDelegate del)
        {
            IObservableWidget widget = proc.RootWidget;
            Tape tape = new Tape(proc, del, hacks);

            IRegistryAccessor reg = new RegistryAccessor();

            foreach (ILEETModual mod in moduals)
            {
                ILEETActionModual actionMod = mod as ILEETActionModual;
                if (actionMod != null)
                {
                    tape.AddListener(actionMod.CreateListener(widget, reg));
                }
            }

            return tape;
        }

        public IInstruction Interpret(string instruction)
        {
            foreach (ILEETModual mod in moduals)
                if (mod.CanCompile(instruction))
                    return mod.CreateInstruction(instruction);
            throw new InvalidInstructionException(instruction);
        }

        public UIElement CreateScriptBuilder()
        {
            return new ScriptBuilder(this, null);
        }

        public UIElement CreateScriptItem(String type, Nil notify)
        {
            if ("ACTION".Equals(type))
            {
                return new ScriptBuilder(this, "ACTION");
            }
            else if ("MOUSE_EVENT".Equals(type))
            {
                return new ScriptBuilder(this, "MOUSE_EVENT");
            }
            else
            {
                foreach (ILEETModual modual in moduals)
                {
                    if (type.Equals(modual.TypeName))
                    {
                        return modual.CreateScriptItemDetails(notify, Box.Processes(), new ElementState(Box, hacks));
                    }
                }
            }
            throw new InvalidInstructionException();
        }



        private List<string> ActionTypes
        {
            get
            {
                List<string> ret = new List<string>();
                foreach (ILEETModual modual in moduals)
                {
                    if (modual is ILEETActionModual || modual is ILEETHackModual)
                        ret.Add(modual.TypeName);
                }
                return ret;
            }
        }

        private List<string> MouseEventTypes
        {
            get
            {
                List<string> ret = new List<string>();
                foreach (ILEETModual modual in moduals)
                {
                    if (modual is ILEETMouseActionModual)
                        ret.Add(modual.TypeName);
                }
                return ret;
            }
        }

        private List<string> CommandTypes
        {
            get
            {
                List<string> ret = new List<string>();
                ret.Add("ACTION");
                ret.Add("MOUSE_EVENT");
                foreach (ILEETModual modual in moduals)
                {
                    if (!(modual is ILEETExtentionModual))
                        ret.Add(modual.TypeName);
                }
                return ret;
            }
        }



        public List<string> CommandsFor(string parentCommand)
        {
            if (parentCommand == null)
                return CommandTypes;
            else if (parentCommand.Equals("ACTION"))
                return ActionTypes;
            else if (parentCommand.Equals("MOUSE_EVENT"))
                return MouseEventTypes;
            else
                return new List<String>();
        }
    }

    

}
